#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logs, time

from ..lib.plugin import MeliponiniPlugin
from ..lib.config import Config
#from ..lib.utils import Utils

config = Config()

CRONFILE = '/etc/meliponini/cron'

def log(s):
    logs.log(s)


class plugin(MeliponiniPlugin):
    def constructor(self, method):
        #self.directory = config.get('dirs.www')
        
        #if method == 'get':
        #    self.addHTTPHandler('/www/list/', self.commandList)
        #    self.addHTTPHandler('/www/backup/', self.commandBackup)
            
        self.addTimer(60, self.timerCheckService)
        
        
    '''
    TIMER checkService
    Comprueba que el servicio Apache esté levantado
    '''
    def timerCheckService(self):
        return

    '''
    GET /cron/list/
    Listamos todas las tareas programadas
    
    El sistema de cron tiene el siguiente formato:
        ip:port:user:pass:dir:name:query
        - ip: IP del demonio de donde extraer la copia de seguridad
        - port: puerto por donde conectarse al demonio
        - user: usuario del demonio
        - pass: contraseña del demonio
        - dir: subdirectorio local dentro del directorio de backups donde almacenar la copia recibida; ej: db
        - query: query solicitada al demonio; ej: /db/backup/zeta/
        
    TODO:
        servername:command:name:data
        - servername: nombre del servidor (previamente se debió configurar datos de conexión)
        - command: comando a realizar (ej: db/backup, svn/backup, etc.)
        - name: nombre identificador de la tarea (ej: nombre de la base de datos)
        - data: datos extra (ej: subdirectorio donde almacenar, como 'db' para las bases de datos) 
    '''
    def commandCronList(self):
        data = []
        # cargamos los datos del cron
        try:
            f = open(CRONFILE, 'r')
            for line in f:
                line = line.strip(' \n')
                if len(line) > 0:
                    data.append(line.split(':'))
                    
            self.responseJSON(data, 200)
        except IOError:
            self.response500()
    
    
    '''
    POST /cron/add/
    Añadimos una nueva entrada al cron
    '''
    def commandAdd(self):
        # Parse the form data posted
        form = cgi.FieldStorage(
            fp = self.rfile, 
            headers = self.headers,
            environ = {
                'REQUEST_METHOD': 'POST',
                'CONTENT_TYPE': self.headers['Content-Type'],
            }
        )
        
        #print form
        if form.has_key('data'):
            line = form['data'].value
        
            # añadimos la línea al cron
            f = open(CRONFILE, 'a')
            f.write(line + '\n')
            f.close()

            # enviamos respuesta
            self.send_response(200)
            self.end_headers()
            self.wfile.write( line )
        
        else:
            # TODO: hacer un bad request
            self.response404('')
            
        return
    
    
    '''
    GET /cron/exec/
    Ejecuta todas las tareas programadas.
    
    Cada tarea programada debe obtener un fichero desde otro serverpaneld, que se almacenará en
    un subdirectorio dentro del directorio local de backups.
    '''
    def commandExec(self):
        log( "[CRON EXEC] start" )
        
        # log que se enviará como respuesta
        log = []
        
        # cargamos los datos del cron
        try:
            f = open(CRONFILE, 'r')
            for line in f:
                line = line.strip(' \n')
                if len(line) > 0:
                    cronip, cronport, cronuser, cronpass, crondir, cronquery = line.split(':')

                    try:
                        # construimos la url con autentificación
                        url = 'http://' + cronip + ':' + cronport + cronquery
                        req = Request(url, None, {'Authorization': 'Basic ' + base64.b64encode( cronuser + ':' + cronpass )})
                        
                        # Open the url
                        fu = urlopen(req)
                        log( "downloading " + url )
                        
                        # en fu.info() tenemos la cabecera con el nombre del fichero
                        # Content-Disposition: attachment; filename="nombre-de-fichero.bz2"
                        filename = None
                        for header in fu.info().items():
                            if header[0].lower() == 'content-disposition':
                                filename = header[1].split('=', 1)[1].strip('"\n')
                                break
                    
                        if filename == None:
                            log( 'Error: filename not set in remote daemon!' )
                            log.append([cronip, cronquery, False, 'filename not set in remote daemon'])
                            continue
                        
                        # configuramos el directorio destino
                        dirname = self.config.BACKUP_DIR + '/' + crondir
                        if not os.path.exists(dirname):
                            os.makedirs(dirname)
                        filename = dirname + '/' + filename
                    
                        # Open our local file for writing
                        fl = open(filename, 'wb')
                        # Write to our local file
                        counter = True
                        while counter:
                            data = fu.read(1024)
                            fl.write(data)
                            counter = len(data) > 0
                        fl.close()
                    
                        log.append([cronip, cronquery, True, filename])
                    
                    #handle errors
                    except HTTPError, e:
                        print "HTTP Error:",e.code , url
                        log.append([cronip, cronquery, False, 'HTTP error'])
                    except URLError, e:
                        print "URL Error:",e.reason , url
                    except IOError:
                        log.append([cronip, cronquery, False, 'IO error'])
                    
            self.responseJSON(log, 200)
            log( "[CRON EXEC] stop" )
                        
        except IOError:
            self.response500()
            return
